package com.lagou.edu.factory;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import com.alibaba.druid.util.StringUtils;
import com.lagou.edu.annotation.Autowired;
import com.lagou.edu.annotation.Service;
import com.lagou.edu.annotation.Transactional;
import org.reflections.Reflections;
/**
 * @author zyy
 * @date 2020/11/21 11:51 下午
 * @description
 */
public class BeanFactory {
    /**
     * 工厂类的两个任务
     * 任务一：扫描包，读取类的注解信息（Service,Transactional），通过反射技术实例化类对象，然后放入Map待用
     * 任务二：提供接口方法：根据id从map中获取Bean(静态方法)
     */
    private static Map<String,Object> map = new HashMap();

    static {
        try {
            //1.扫描包 找到带有@Service的类通过反射实例化对象并放到map集合中
            Reflections reflections = new Reflections("com.lagou.edu");
            //1.1获取注解为Service的集合
            Set<Class<?>> serviceAnnotateWithClassSet = reflections.getTypesAnnotatedWith(Service.class);
            for (Class<?> aClass : serviceAnnotateWithClassSet) {
                //实例化对象
                Object bean = aClass.newInstance();
                Service service = aClass.getAnnotation(Service.class);

                //注解有无value属性值 有则获取属性值作为Bean名称
                if(StringUtils.isEmpty(service.value())){
                    String[] names = aClass.getName().split("\\.");
                    map.put(names[names.length - 1],bean);
                    System.out.println(names[names.length - 1]);
                }else {
                    map.put(service.value(), bean);
                    System.out.println(service.value());
                }
            }
            System.out.println("============");
            //2.通过@Autowire注解去维护bean之间的依赖关系
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                Object obj = entry.getValue();
                //bean对象的类
                Class<?> aClass = obj.getClass();

                //获取属性集合
                Field[] fields = aClass.getDeclaredFields();
                //遍历属性 若含有@Autowired注解则注入
                for (Field field : fields) {
                    if(field.isAnnotationPresent(Autowired.class)){
                        String[] names = field.getType().getName().split("\\.");
                        //AccountDao
                        String name = names[names.length-1];
                        Method[] methods = aClass.getMethods();
                        for (int i = 0; i < methods.length; i++) {
                            Method method = methods[i];
                            //method.getName() = setAccountDao
                            //setAccountDao(AccountDao accountDao)
                            if (method.getName().equalsIgnoreCase("set"+name)) {
                                method.invoke(obj,map.get(name));
//                                System.out.println("进来了：name +\"-\"+ method.getName() = " + name +"-"+ method.getName());
                            }
                        }
                    }
                }
                //若类含有@Transactional注解则修改对象为代理对象
                if(aClass.isAnnotationPresent(Transactional.class)){
                    //获取代理工厂
                    ProxyFactory proxyFactory = (ProxyFactory) BeanFactory.getBean("ProxyFactory");
                    //service层是否实现接口的情况 【jdk还是cglib】
                    Class<?>[] interfaces = aClass.getInterfaces();
                    if (interfaces!=null && interfaces.length>0) {
                        //使用JDK代理
                        obj = proxyFactory.getJdkProxy(obj);
                    }else {
                        //使用cglib代理
                        obj = proxyFactory.getCglibProxy(obj);
                    }
                }
                // 把Object代理对象重新放到map中
                map.put(entry.getKey(),obj);
            }

        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }


    /**
     * 根据Beanid 获取bean
     * @param id beanID
     * @return
     */
    public static Object getBean(String id){
        return map.get(id);
    }
}
